package com.netty.quartz.util;

import com.netty.common.constant.ScheduleConstants;
import com.netty.common.enums.ExceptionEnum;
import com.netty.common.exception.BizException;
import com.netty.quartz.entity.SysJob;
import org.quartz.*;

/** 任务调度工具类
 * @author LiuXiaoYu
 * @date 2021/10/16- 9:01
 */
public class ScheduleUtils {
    /**
     * 创建定时任务
     * @param scheduler 调度器
     * @param sysJob 任务详细信息
     */
    public static void createScheduleJob(Scheduler scheduler, SysJob sysJob) throws SchedulerException {
        //1.判断任务是否需要并发执行
        Class<? extends Job> jobClass=getConcurrentJobClass(sysJob);
        //2.构建job信息
        //得到jobId->jobKey
        Long jobId=sysJob.getJobId();
        //得到jobGroup
        String jobGroup=sysJob.getJobGroup();
        //3.创建jobDetail
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put(ScheduleConstants.TASK_PROPERTIES,sysJob);
        JobDetail jobDetail= JobBuilder.newJob(jobClass)
                .usingJobData(jobDataMap).withIdentity(ScheduleConstants.TASK_CLASS_NAME+jobId,jobGroup)
                .build();
        //4.创建Cron表达式任务创建器
        CronScheduleBuilder cronScheduleBuilder=CronScheduleBuilder.cronSchedule(sysJob.getCronExpression());
        //这里单独提出来cron任务创建器是为了设置失火策略(失火策略由前端指定)
        cronScheduleBuilder = setMisFireStrategy(sysJob, cronScheduleBuilder);
        //5.创建CronTrigger
        CronTrigger cronTrigger=TriggerBuilder.newTrigger()
                .withIdentity(ScheduleConstants.TASK_CLASS_NAME+jobId,jobGroup)
                //SimpleTrigger 6种失火策略 其他的3种 这里使用CronTrigger
                .withSchedule(cronScheduleBuilder)
                .build();
        //7.判断job是否已经存在 存在就先移除然后在创建
        if (scheduler.checkExists(JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME+jobId,jobGroup))){
            scheduler.deleteJob(JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME+jobId,jobGroup));
        }
        //8.执行任务
        scheduler.scheduleJob(jobDetail, cronTrigger);
        scheduler.start();
        //9.根据前端传来的是否需要创建时就暂停任务
        if (sysJob.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) {
            scheduler.pauseJob(JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME+jobId, jobGroup));
        }
//        else {
//            scheduler.resumeJob(JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME+jobId, jobGroup));
//        }
    }

    /**
     * 设置失火策略
     * @param sysJob 任务信息对象
     * @param cronScheduleBuilder cron表达式任务构建器
     * @return
     */
    private static CronScheduleBuilder setMisFireStrategy(SysJob sysJob, CronScheduleBuilder cronScheduleBuilder) {
        switch (sysJob.getMisfirePolicy()){
           /* 默认：错过的合并,于当前时间执行一次，
             不修改调度时间，按计划等待下一次调度
             （等价于下面的 WithMisfireHandlingInstructionFireAndProceed）*/
            case ScheduleConstants.MISFIRE_DEFAULT:
                return cronScheduleBuilder;
         /*   错过多少次，初次执行的时候追赶多少次，追赶的次数的时间是按原规律执行的时间，
             然后按照原规律进行正常后续调度*/
            case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
                return cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires();
            //无论错过多少次，均在初次运行的时候，即当前时间执行一次，
            // 后续的执行仍按照原规律进行执行
            case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
                return cronScheduleBuilder.withMisfireHandlingInstructionFireAndProceed();
            //无论错过多少次，均忽略，后续的执行仍按照原规律进行执行
            case ScheduleConstants.MISFIRE_DO_NOTHING:
                return cronScheduleBuilder.withMisfireHandlingInstructionDoNothing();
            default:
                throw new BizException(ExceptionEnum.ERROR,"此失火策略"+sysJob.getMisfirePolicy()+"不能作用于该任务");
        }
    }

    /**
     * 判断任务是否需要并发执行
     * 0允许 1禁止
     * @param sysJob 构建的任务对象信息
     * @return class
     */
    private static Class<? extends Job> getConcurrentJobClass(SysJob sysJob) {
        return "0".equals(sysJob.getConcurrent())?ConcurrentJob.class: NoCocurrentJob.class;
    }
}
